package org.parademo.web.controller;

import org.parademo.model.ProposalEntity;
import org.parademo.model.ProposalStatusEntity;
import org.parademo.model.TopicEntity;
import org.parademo.model.UserEntity;
import org.parademo.service.ProposalService;
import org.parademo.service.ProposalStatusService;
import org.parademo.service.TopicService;
import org.parademo.service.UserService;
import org.parademo.service.security.SecurityUtil;
import org.parademo.web.model.ProposalFormView;
import org.parademo.web.model.ProposalListView;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static org.parademo.web.controller.util.ViewFormatterUtil.*;

@Controller
public class ProposalController {
    
    private final UserService userService;
    private final ProposalService proposalService;
    private final ProposalStatusService proposalStatusService;
    private final TopicService topicService;
    private final CustomDateEditor customDateEditor;

    public ProposalController(UserService userService,
                              ProposalService proposalService,
                              ProposalStatusService proposalStatusService,
                              TopicService topicService,
                              CustomDateEditor customDateEditor) {
        this.userService = userService;
        this.proposalService = proposalService;
        this.proposalStatusService = proposalStatusService;
        this.topicService = topicService;
        this.customDateEditor = customDateEditor;
    }

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(Date.class, customDateEditor);
    }

    @RequestMapping(value = "/proposals", method = RequestMethod.GET, params = "create")
    public String showCreateProposalForm(@ModelAttribute("proposal") ProposalFormView proposalFormView,
                                         Model model) {

        model.addAttribute("topics", topicService.getTopics());

        return "createProposalForm";
    }

    @RequestMapping(value = "/proposals", method = RequestMethod.POST)
    public String createProposal(@ModelAttribute("proposal") ProposalFormView proposal,
                                 BindingResult bindingResult,
                                 Model model) {
        proposal.validateUsing(bindingResult);

        if (bindingResult.hasErrors()) {
            return showCreateProposalForm(proposal, model);
        }

        proposalService.createProposal(proposal);

        return "redirect:/my-proposals";
    }

    @RequestMapping(value = "/proposals/{id}", method = RequestMethod.GET)
    public String showViewProposalForm(@ModelAttribute("proposal") ProposalFormView proposalFormView,
                                       @PathVariable("id") Long proposalId,
                                       Model model) {

        ProposalFormView proposal = proposalService.getProposalById(proposalId);

        model.addAttribute("proposal", proposal);
        model.addAttribute("canSubmitProposal", !proposal.isSubmitted());

        return "viewProposalForm";
    }

    @RequestMapping(value = "/proposals/{id}", method = RequestMethod.POST, params = "submit")
    public String submitProposal(@PathVariable("id") Long proposalId) {
        proposalStatusService.submitProposal(proposalId);

        return "redirect:/my-proposals";
    }

    @RequestMapping("/my-proposals")
    public String showProposalsForUser(Model model) {
        String userName = SecurityUtil.getCurrentUserName();

        UserEntity user = userService.getUserByUserName(userName);
        if (user == null) {
            model.addAttribute("username", userName);

            return "proposalList_unknownUser";
        }

        model.addAttribute(
                "user",
                formatUser(user)
        );

        List<ProposalEntity> proposals = proposalService.getProposalsForUser(user.getId());

        List<ProposalListView> viewProposals = getProposalsForView(proposals);

        model.addAttribute("proposals", viewProposals);

        return "proposalList";
    }

    private List<ProposalListView> getProposalsForView(List<ProposalEntity> proposals) {
        List<ProposalListView> viewProposals = new ArrayList<ProposalListView>();

        for (ProposalEntity proposal : proposals) {
            viewProposals.add(
                    getProposalForView(proposal)
            );
        }

        return viewProposals;
    }

    private ProposalListView getProposalForView(ProposalEntity proposal) {
        ProposalListView proposalListView = new ProposalListView();

        proposalListView.setId(
                proposal.getId()
        );
        proposalListView.setTitle(
                proposal.getTitle()
        );
        proposalListView.setDescription(
                proposal.getDescription()
        );
        proposalListView.setInternal(
                formatBoolean(
                        proposal.isInternal()
                )
        );
        proposalListView.setTopic(
                getTopic(proposal)
        );
        proposalListView.setStatus(
                getStatus(proposal)
        );

        return proposalListView;
    }

    private String getTopic(ProposalEntity proposal) {
        TopicEntity topic = proposal.getTopic();

        if (topic == null) {
            return formatNull();
        }

        return topic.getName();
    }

    private String getStatus(ProposalEntity proposal) {
        ProposalStatusEntity status = proposal.getStatus();

        if (status == null) {
            return formatNull();
        }

        return status.getTitle();
    }
}
